<template>
  <div class="chart" ref="chartWrap">
    <div class="chart-select" v-if="hasColHeader">
      <div class="label">{{ label }}</div>
      <a-select
        class="select"
        dropdownClassName="chart-drop-down"
        v-model="selectedItem"
        style="width: 100px"
        :options="selectOptions"
        @change="onChange">
      </a-select>
    </div>
    <div class="chart-select" v-if="hasStatsSelect">
      <div class="label">{{ $i18n('reportengine.stats.statistical.item') }}</div>
      <a-select
        class="select"
        dropdownClassName="chart-drop-down"
        v-model="selectedStatsItem"
        style="width: 100px"
        :options="statsFieldsOptions"
        @change="onChange">
      </a-select>
    </div>
    <div class="empty" v-if="showEmpty">
      <div>{{ $i18n("reportengine.result.chart.txt1") }}</div>
      <div>{{ $i18n("reportengine.result.chart.txt2") }}</div>
    </div>
    <div id="chart" ref="canvasEchart"></div>
  </div>
</template>

<script>
import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/pie'
import 'echarts/lib/chart/funnel'
import 'echarts/lib/chart/radar'
import 'echarts/lib/chart/map'
import 'echarts/lib/component/title'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/grid'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/legendScroll'
import 'echarts/lib/component/dataZoom'

export default {
  name: 'Chart',
  props: {
    data: {
      type: Object,
    },
    list: {
      type: Object,
    },
    type: {
      type: String
    },
    commonData: {
      type: Object
    }
  },
  data() {
    return {
      theme: {
        color: ['#64d0c6','#1f85ec','#5246c5','#ff6d68','#26a3ed','#f9b954','#24bde3','#00d58b'],
        textStyle: {fontFamily: '微软雅黑, Arial, Verdana, sans-serif'}
      },  // 主题
      defaultParams: {
        axisMarginLeft: 60,
        axisMarginRight: 15,
        axisMarginBottom: 38,
        pieTop: 55,
        radarTop: 55,
        funnelTop: 0,
        axisMarginTop: 25
      },  // 原样式
      selectedItem: 0,
      selectedData: [],
      selectedStatsItem: 0,
      myChart: null,
      chartStyle: {
        width: 0,
        style: 0
      },
      wordNum: 0,
      wordColNum: 0,
      dataZoom: {},
      geoData: null,
      showEmpty: false
    }
  },
  watch: {
    'commonData': {
      handler(v) {
        this.$nextTick(() => {
          this.initChart()
        })
      },
      deep: true,
      immediate: true
    }
  },
  computed: {
    label() {
      return this.data?.formCondMap?.colHeaders?.aliasDisplay || ''
    },
    selectOptions() {
      let options = this.list?.coldata || []
      options = options.map((item, index) => {
        return {
          value: index,
          label: item[0]
        }
      })
      return options
    },
    // 统计项字段
    statsFields() {
      return this.data?.formCondMap?.statsFields || []
    },
    statsFieldsOptions() {
      let options = this.data?.formCondMap?.statsFields || []
      options = this.statsFields.map((item, index) => {
        return {
          value: index,
          label: item.aliasDisplay
        }
      })
      return options
    },
    // 是否有列表头
    hasColHeader() {
      return this.data?.formCondMap?.colHeaders
    },
    // 分组统计字段数据
    colData() {
      return this.list?.coldata || []
    },
    rowHeaderKeys() {
      const rowHeaders = this.data?.formCondMap?.rowHeaders || []
      const keyList = rowHeaders.map(item => item.aliasTableName + '_' + item.name)
      return keyList
    },
    // 网格数据
    gridData() {
      return {
        borderWidth: 0,
        top: this.defaultParams.axisMarginTop,
        right: this.defaultParams.axisMarginRight,
        bottom: this.defaultParams.axisMarginBottom,
        left: this.defaultParams.axisMarginLeft
      }
    },
    hasStatsSelect() {
      return this.statsFields.length > 1 && (this.type === '5' || this.type === '6' || this.type === '9')
    }
  },
  methods: {
    onChange() {
      this.wordNum = 0
      this.wordColNum = 0
      this.draw()
    },
    initChart() {
      const style = window.getComputedStyle(this.$refs.chartWrap)
      let h = parseInt(style.height)

      this.hasColHeader && (h = h - 32)
      this.hasStatsSelect && (h = h - 32)
      this.chartStyle = {
        width: parseInt(style.width),
        height: h
      }
      echarts.registerTheme('theme', this.theme)
      this.draw()
    },
    // 生成区域缩放轴
    createDataZoom(location = 'bottom', allLength) {
      let dataZoom = null
      const defalutConfig = {
        margin: 10,
        selfSize: 10,
        fontSize: 12
      }
      
      if (location === 'bottom') {
        // x轴缩放
        const canvasW = this.chartStyle.width - this.gridData.right - this.gridData.left

        // 是否需要缩放轴
        if (1.1 * canvasW < allLength) {
          dataZoom = {
            show: true,
            z: 1,
            height: defalutConfig.selfSize,
            bottom: defalutConfig.margin,
            orient: 'horizontal',
            xAxisIndex: 0,
            start: 0,
            end: Math.abs(( canvasW / allLength) * 100)
          }
          this.gridData.bottom = dataZoom.height + this.defaultParams.axisMarginBottom + dataZoom.bottom + defalutConfig.margin

          // 缩放时，重新计算x轴可显示字数
          this.myChart.on('datazoom', (params) => {
            const colNum = (Math.ceil(params.end - params.start) / 100) * this.commonData.axisData.xAxis.length
            this.wordNum = Math.floor((canvasW / colNum)) / defalutConfig.fontSize
          });
        }
      } else {
        // y轴缩放
        const canvasH = this.chartStyle.height - this.gridData.top - this.gridData.bottom

        // 是否需要缩放轴
        if (1.1 * canvasH < allLength) {
          dataZoom = {
            show: true,
            z: 1,
            width: defalutConfig.selfSize,
            right: defalutConfig.margin,
            orient: 'vertical',
            yAxisIndex: 0,
            start: 0,
            end: Math.abs(( canvasH / allLength) * 100)
          }
          this.gridData.right = dataZoom.width + this.defaultParams.axisMarginRight

          // 缩放时，重新计算y轴可显示字数
          // this.myChart.on('datazoom', (params) => {
          //   const colNum = (Math.ceil(params.end - params.start) / 100) * this.commonData.axisData.xAxis.length
          //   this.wordColNum = canvasH / colNum / 14
          // });
        }
      }

      this.dataZoom = dataZoom
    },
    draw() {
      let option = {}
      this.selectedData = this.hasColHeader ? this.commonData.seriesData[this.selectedItem] : this.commonData.seriesData
      
      if (!this.selectedData || !this.selectedData.length) {
        // this.showEmpty = true
        this.myChart = null
        return
      }
      this.showEmpty = false
      this.myChart && (this.myChart.clear())

      this.myChart = echarts.init(this.$refs.canvasEchart, 'theme', {
        ...this.chartStyle
      })
      this.myChart.showLoading('default', {
        text: 'loading...'
      })

      // 地图
      if (this.type === '8') {
        this.drawMap()
        return
      }

      switch (this.type) {
        case '1': // 柱状图
        case '2': // 条形图
          option = this.getBarOption()
          break
        // case '2': // 条形图
        //   option = this.getColBarOption()
        //   break
        case '3': // 折线图
        case '4': // 面积图
          option = this.getLineOption()
          break
        case '5': // 饼状图
        case '6': // 环形图
          option = this.getPieOption()
          break
        case '7': // 雷达图
          option = this.getRadarOption()
          break
        case '9': // 漏斗图
          option = this.getFunnelOption()
          break
      }

      console.log('option', option)
      this.myChart.hideLoading()
      if (option) {
        this.showEmpty = false
        this.myChart.setOption(option)
      } else {
        this.showEmpty = true
      }
    },
    // 柱状图
    getBarOption() {
      const isBar = this.type === '1'
      const allWidth = (isBar ? 90 : 50) * this.selectedData.length * this.commonData.axisData.xAxis.length
      let option = {}
      isBar ? this.createDataZoom('bottom', allWidth) : this.createDataZoom('right', allWidth)

      option = {
        tooltip: {
          enterable: true,
          trigger: 'axis',
          textStyle: {
            fontSize: 14
          }
        },
        legend: {
          type: 'scroll',
          data: this.commonData.legendData
        },
        series: this.selectedData.map((item, index) => {
          return {
            name: this.commonData.legendData[index],
            type: 'bar',
            barMaxWidth: 35,
            barGap: '0',
            data: item.map(d => d.v)
          }
        }),
        dataZoom: this.dataZoom,
        grid: this.gridData
      }

      if (isBar) {
        // 柱状图
        option = {
          ...option,
          xAxis: {
            type: 'category',
            data: this.commonData.axisData.xAxis,
            axisLabel: {
              interval: 0,
              formatter: this.xAxisFormatter
            }
          },
          yAxis: {
            type: 'value'
          }
        }
      } else {
        // 条形图
        option = {
          ...option,
          yAxis: {
            type: 'category',
            data: this.commonData.axisData.xAxis,
            axisLabel: {
              interval: 0,
              formatter: this.yAxisFormatter
            }
          },
          xAxis: {
            type: 'value'
          }
        }
      }

      return option.series.length ? option : null
    },
    // 折线图 or 面积图
    getLineOption() {
      let option = {}
      const allWidth = 40 * this.commonData.axisData.xAxis.length
      this.createDataZoom('bottom', allWidth)

      option = {
        tooltip: {
          enterable: true,
          trigger: 'axis',
          textStyle: {
            fontSize: 14
          }
        },
        xAxis: {
          type: 'category',
          data: this.commonData.axisData.xAxis,
          axisLabel: {
            interval: 0,
            formatter: this.xAxisFormatter
          }
        },
        yAxis: {
          type: 'value'
        },
        legend: {
          type: 'scroll',
          data: this.commonData.legendData
        },
        series: this.selectedData.map((item, index) => {
          return {
            name: this.commonData.legendData[index],
            type: 'line',
            data: item.map(d => d.v),
            itemStyle: this.type === '4' ? { normal: { areaStyle: { type: 'default' } } } : {}
          }
        }),
        dataZoom: this.dataZoom,
        grid: this.gridData
      }

      return option.series.length ? option : null
    },
    // 饼图、环形图
    getPieOption() {
      const dataKey = this.hasColHeader ? `${this.selectedItem}_${this.selectedStatsItem}` : this.selectedStatsItem
      const maxIndex = this.data.pageSize - 1
      const dataLen = this.commonData.allSeriesData.length
      let legendData = [], serieDatas = [], total = 0, r = this.getRadius()

      this.commonData.allSeriesData.forEach((item, i) => {
        let value = item[dataKey].v

        if (i < maxIndex) {
          legendData[i] = item.itemName
          serieDatas[i] = {
            value,
            rowIndex : item.rowIndex,
            name: item.itemName
          }
        } else if (i === maxIndex) {
          if (i === (dataLen - 1)) {
            legendData[i] = item.itemName
          } else {
            // 数据条数超出pagesize，则最后一项数据label显示为‘其他’
            let other = $.i18n('common.other.label')
            legendData[i] = (null == other ) ? '' : other
          }
          serieDatas[i] = {
            value,
            rowIndex : item.rowIndex,
            name: legendData[i]
          }
        } else {
          // 统计超出pagesize的数据的total
          serieDatas[maxIndex].value = serieDatas[maxIndex].value + item[dataKey].v
        }
      })

      // 统计数据总和
      serieDatas.forEach(item => total = total + item.value || 0)
      if(total < 1e-5 && total > -1e-5) total = 0
      if (!total) {
        this.showEmpty = true
        return null
      }

			let option = {
			  title: this.type === '6'
          ? {
            text: total + '\n' + this.statsFieldsOptions[this.selectedStatsItem].label,
            textStyle: {
              fontSize : 20
            },
            left: 'center',
            top: (this.chartStyle.height * this.defaultParams.pieTop / 100 - 20)
          } :
          {}
        ,
        legend: {
          type: 'scroll',
          data: legendData
        },
				tooltip: {
					enterable: true,
					trigger: 'item',
					formatter: '{b}<br/>{a} : {c} ({d}%)',
					textStyle: {
            fontSize: 14
          }
				},
				series: [{
					name: this.statsFieldsOptions[this.selectedStatsItem].label,
					type: 'pie',
					radius: this.type === '5' ? r * 0.6 : [r * 0.8, r * 0.6],
					center: ['50%', this.defaultParams.pieTop + '%'],
					label: {
            show: true,
            position: 'outside',
            formatter: '{d}%'
          },
					data: serieDatas
				}]
			}

      return serieDatas?.length ? option : null
    },
    // 雷达图
    getRadarOption() {
      let option = {}
      let maxVal = 1

      let dataList = this.selectedData.map((item, index) => {
        const value = item.map(d => d.v)
        maxVal = Math.max(maxVal, ...value)
        return {
          name: this.commonData.legendData[index],
          value,
          itemNames: this.commonData.axisData.xAxis
        }
      })

      let indicatorArr = this.commonData.axisData.xAxis.map(item => {
        return {
          name: item,
          max: maxVal
        }
      })

      option = {
        tooltip: {
          enterable: true,
          trigger: 'item',
          textStyle: {
            fontSize: 14
          }
        },
        radar: [
          {
            center: ['50%', this.defaultParams.radarTop + '%'],
            radius: this.getRadius() * 0.7,
            indicator: indicatorArr,
            name: {
              textStyle: {
                color: '#333333'
              }
            }
          }
        ],
        legend: {
          type: 'scroll',
          data: this.commonData.legendData
        },
        series: [
          {
            type: 'radar',
            data: dataList
          }
        ]
      }

      return dataList?.length ? option : null
    },
    // 漏斗图
    getFunnelOption() {
      const dataKey = this.hasColHeader ? `${this.selectedItem}_${this.selectedStatsItem}` : this.selectedStatsItem
      const digitNum = this.statsFields[this.selectedStatsItem].digitNum
      let dataList = this.commonData.allSeriesData.slice(0, Math.min(this.data.pageSize, this.commonData.allSeriesData.length)) || [] // 原逻辑-最多只要10条数据
      let total = 0

      for (let i = (dataList.length - 1); i >= 0; i --) {
        let val = dataList[i][dataKey].v || 0
        total = total +  parseFloat(val)
        dataList[i] = {
          value: total,
          v: val,
          name: this.commonData.axisData.xAxis[i]
        }
      }

      let option = {
        tooltip: {
          enterable: true,
          trigger: 'item',
          formatter: (p) => {
            let ret =  escapeStringToHTML(p.name)
            let percent = (total === 0) ? 0 : parseFloat(p.data.v / total * 100).toFixed(digitNum)
            ret += '<br/>' + $.i18n("reportengine.result.chart.funnel.proportion") + ':' + p.data.v + '/' + percent + '%'
            return ret
          },
          textStyle: { fontSize: 14 }
        },
        series: [
          {
            name: this.hasStatsSelect ? '' : this.statsFieldsOptions[this.selectedStatsItem].label,
            type: 'funnel',
            sort: 'descending',
            top: 0,
            bottm: 10,
            min: 0,
            max: total,
            maxSize: '100%',
            left: '15%',
            width: '70%',
            label: {
              show: true,
              position: 'left',
              formatter: '{b}'
            },
            emphasis: {
              label: {
                show: true,
                formatter: '{b}'
              }
            },
            data: dataList
          }
        ]
      }
      // OA-233451 单表，多表配置了漏斗图，配置到v5栏目上，当漏斗图的数据是0的时候，栏目上不显示图，见截图
      if(option.series[0].max == 0 && option.series[0].min == 0){
        option.series[0].max = 1
      }
      return dataList?.length ? option : null
    },
    // 地图
    drawMap() {
      let option = {}
      let series = this.commonData.legendData.map(item => {
        return {
          name: item,
          type: 'map',
          map: 'china',
          data: new Array(this.selectedData.length).fill({})
        }
      })
      this.selectedData.forEach((item, index) => {
        item.forEach((d, i) => {
          series[index].data[i] = {
            name: this.commonData.axisData.xAxis[i],
            value: d.v,
            selected: true
          }
        })
      })

      option = {
        tooltip: {
          enterable: true,
          trigger: 'item',
          textStyle: {
            fontSize: 14
          },
          formatter: (param) => {
            let ret = param.name
            const legendData = this.commonData.legendData
            const data = series.map(item => {
              return item.data && item.data[param.dataIndex] || ''
            })
            legendData.forEach((item, i) => {
              ret = ret + '<br/>' + escapeStringToHTML(item)
              if (data[i] !== '') {
                ret = ret + ':' + data[i].value
              }
            })
            return ret
          }
        },
        legend: {
          type: 'scroll',
          data: this.commonData.legendData
        },
        series
      }

      if (this.commonData.geoData) {
        echarts.registerMap('china', this.commonData.geoData)
        this.myChart.hideLoading()
        this.myChart.setOption(option)
        return
      }
    },
    // 计算半径
    getRadius() {
      let h = this.chartStyle.height, w = this.chartStyle.width / 2
			let t = h * this.defaultParams.pieTop / 100, b = h - t
			return Math.min(t, b, w) || 1
    },
    // x轴文字处理
    xAxisFormatter(value) {
      let v = ''
      const chartWidth = this.chartStyle.width - this.gridData.right - this.gridData.left // 图形实际宽度
      const zoomHeight = (this.dataZoom && this.dataZoom.height) ? (this.dataZoom.height + 20) : 0 // 缩放轴区域所占高度（包含上下10px的margin）
      const rowLen = parseInt((this.gridData.bottom - zoomHeight) / 12)  // x轴文字区域能显示的文字行数

      if (!this.wordNum) {
        // 初始时计算x轴可显示字数
        const colNum = Math.ceil(((this.dataZoom && this.dataZoom.end) ? (this.dataZoom.end - this.dataZoom.start) / 100 : 1) * this.commonData.axisData.xAxis.length)
        this.wordNum = Math.floor((chartWidth / colNum)) / 12
      }
  
      // 按x轴可显示行数、字数格式化数据
      if(value != undefined ) {
        for(let i = 0; i < rowLen; i ++) {
          if (value.length <= this.wordNum) {
            v = v + value
            break
          }
          if (i == (rowLen - 1)) {
            v = v + value.substr(0, this.wordNum - 1) + '...'
          } else {
            v = v + value.substr(0, this.wordNum) + '\n'
            value = value.substr(this.wordNum, value.length)
          }
        }
      }

      return v
    },
    // y轴文字处理
    yAxisFormatter(value) {
      // let v = ''
      // const chartHeight = this.chartStyle.height - this.gridData.bottom - this.gridData.top // 图形实际高度
      // const wordNum = parseInt(this.gridData.left / 14)  // x轴文字区域能显示的文字行数

      // if (!this.wordColNum) {
      //   // 初始时计算y轴可显示行数
      //   const colNum = Math.ceil((this.dataZoom.end ? (this.dataZoom.end - this.dataZoom.start) / 100 : 1) * this.commonData.axisData.xAxis.length)
      //   this.wordColNum = Math.floor((chartHeight / colNum)) / 14
      // }
  
      // // 按x轴可显示行数、字数格式化数据
      // if(value != undefined ) {
      //   for(let i = 0; i < this.wordColNum; i ++) {
      //     if (value.length <= wordNum) {
      //       v = v + value
      //       break
      //     }
      //     if (i == (this.wordColNum - 1)) {
      //       v = v + value.substr(0, wordNum - 1) + '...'
      //     } else {
      //       v = v + value.substr(0, wordNum) + '\n'
      //       value = value.substr(wordNum, value.length)
      //     }
      //   }
      // }

      // 原逻辑
      let baseSize = parseInt(this.gridData.left / 14)
      let v = value

      if (value != undefined && value.length > baseSize) {
        v = value.substr(0, baseSize) + '\n'
        value = value.substr(baseSize, value.length)
        if (value.length > baseSize - 1) {
          v = v + value.substr(0, baseSize-1) + '...'
        } else {
          v = v + value.substr(0, baseSize - 1)
        }
      }

      return v
    }
  }
}
</script>

<style lang="scss" scoped>
.chart {
  height: 250px;
  margin-bottom: 20px;
  &-select {
    display: flex;
    align-items: center;
    .select {
      margin-left: 5px;
    }
  }
  .empty {
    margin-top: 70px;
    font-size: 16px;
    color: #666666;
    text-align: center;
  }
}
</style>
<style lang="scss">
.chart-drop-down .ant-select-dropdown-menu-item {
  height: 32px;
}
</style>
